#include "Map.h"

Map::Map():
	mpSprites(nullptr),
	mpTiles(nullptr),
	mNumSprites(0),
	mTileSizeW(0),
	mTileSizeH(0),
	mColumns(0),
	mRows(0)
{
}
Map::~Map()
{
}

void Map::Load(const char* pLevel, const char* pTexturePack)
{
	Unload();

	if(!LoadLevel(pLevel))
	{
		Unload();
		return;
	}
	else if(!LoadTexturePack(pTexturePack))
	{
		Unload();
		return;
	}

}
void Map::Unload()
{
	for(int i = 0; i < mNumSprites; ++i)
	{
		mpSprites[i].Unload();
	}
	delete [] mpSprites;

	delete [] mpTiles;
	mpTiles = nullptr;
	mTileSizeW = 0;
	mTileSizeH = 0;
	mColumns = 0;
	mRows = 0;
}


void Map::Render(const SVector2& viewOffset)
{
	for(int y = 0; y < mRows; ++y)
	{
		for(int x = 0; x < mColumns; ++x)
		{
			const int index = GetIndex(x, y);
			SVector2 pos((float)x * mTileSizeW, (float)y* mTileSizeH);
			SVector2 renderPosition = pos - viewOffset;
			mpSprites[mpTiles[index]].SetPosition(renderPosition);
			mpSprites[mpTiles[index]].Render();
		}
	}
}
void Map::RenderIsometric(const SVector2& viewOffset)
{

	for(int y = 0; y < mRows; ++y)
	{
		for(int x = 0; x < mColumns; ++x)
		{
			const int index = GetIndex(x,y);
			SVector2 pos(((float)(x-y)*(mTileSizeW/2)), ((float)(x+y)* (mTileSizeH/2)));
			mpSprites[mpTiles[index]].SetPosition(pos+viewOffset);
			mpSprites[mpTiles[index]].Render();
		}
	}
}
bool Map::LoadLevel(const char* pLevel)
{
	FILE* pFile = nullptr;//set ptr to hold
	fopen_s(&pFile, pLevel, "r");//(hold,from,mode)
	if(pFile == nullptr)
	{
		return false;
	}
	else
	{
		//*s read a string then discard it, 
		fscanf(pFile, "%*s %d", &mTileSizeH);//get tile size tc
		fscanf(pFile, "%*s %d", &mTileSizeW);
		fscanf(pFile, "%*s %d", &mColumns);
		fscanf(pFile, "%*s %d", &mRows);
		//array
		mpTiles = new int[mColumns*mRows];

		fgetc(pFile);//eat the space
		for(int y = 0; y < mRows; ++y)
		{
			for(int x = 0; x < mColumns; ++x)
			{
				const int index = GetIndex(x, y);
				mpTiles[index] = fgetc(pFile) - '0';
			}
			fgetc(pFile);//eat space
		}
	}
	fclose(pFile);
	return true;
}
bool Map::LoadTexturePack(const char* pTexturePack)
{
	FILE* pFile = nullptr;//set ptr to hold
	fopen_s(&pFile, pTexturePack, "r");//(hold,from,mode)
	if(pFile == nullptr)
	{
		return false;
	}
	else
	{
		//*s read a string then discard it, 
		fscanf(pFile, "%*s %d", &mNumSprites);//get tile size tc
		mpSprites = new SGE_Sprite[mNumSprites];

		char buffer[256];
		for(int i = 0; i < mNumSprites; ++i)
		{
			fscanf_s(pFile, "%s", buffer, 256);
			mpSprites[i].Load(buffer);
		}
	}
	fclose(pFile);
	return true;
}

int Map::GetIndex(int x, int y) const
{
	return x + (y * mColumns);
}

bool Map::TestCollision(const SLineSegment& segment, SRect& rect)const
{
	//check out of box
	if (segment.from.x < 0.0f || segment.from.x >= getWidth()||
		segment.from.y < 0.0f || segment.from.y >= getHeight()||
		segment.to.x < 0.0f || segment.to.x >= getWidth() ||
		segment.to.y < 0.0f || segment.to.y >= getHeight())
	{
		return false;
	}

	//get libne val
	const int minX = (int)(segment.from.x / mTileSizeW);
	const int minY = (int)(segment.from.y / mTileSizeW);
	const int maxX = (int)(segment.to.x / mTileSizeH);
	const int maxY = (int)(segment.to.y / mTileSizeH);
	
	//add empty box
	rect = SRect();
	//loop through tile!!
	bool collision = false;
	for(int y = minY; y <= maxY; ++y)
	{
		for(int x = minX; x <= maxX; ++x)
		{
			if(IsBlocked(x,y))
			{
				rect += GetBoundingBox(x,y);//if is blocked, add box to obstacle, next add box to next obstacle coor and so on.(combined box) 
				collision = true;
			}
		}
	}
	return collision;
}

bool Map::IsBlocked(int x, int y) const
{
	const int index = GetIndex(x,y);
	const int type = mpTiles[index];
	/*if(type > 1)
	{}*/
	return (type > 1);
}

SRect Map::GetBoundingBox(int x, int y) const
{
	SRect boundingBox;
	boundingBox.min.x = x * mTileSizeW;
	boundingBox.min.y = y * mTileSizeH;
	boundingBox.max.x = ((x+1) * mTileSizeW)-1;
	boundingBox.max.y = ((y+1) * mTileSizeH)-1;

	return boundingBox;
}